
#ifndef _CALCULATORCORE_
#define _CALCULATORCORE_
#include "Common/Definitions.h"

#include "Common/Strings.h"
#include "Params.h"
#include "OperationMapper.h"

namespace ttg
{
	namespace extras
	{
		template<class T> class Calculator;
	}
}

namespace ttg_internal
{
	//Non-generic routines.
	class CalculatorRoutines
	{
		private:
			//Defines current parser state.
			enum State
			{
				OPERAND_EXPECTED,		//next lexem should be operand (e.g. 1).
				OPERATION_EXPECTED		//next lexem should be operantion (e.g. +).
			};
			static int getPriority(OperationInfo::OperationName ops);
		private:
			//Tries to build function with given name. Arguments will be getted from StringSplitter.
			static OperationInfo *buildFunction(std::string &name,
												ttg::strings::StringSplitter &sp,
												int &n,
												ttg::extras::Params *params);
			//Build wrapper around next operand (it can be (), constant or variable).
			static OperationInfo *buildWrapper(ttg::strings::StringSplitter &sp,
											   int &n,
											   ttg::extras::Params *params);
			//Parses given lexem list by operand and operations.
			//Note: () is one operand.
			static bool parse(ttg::strings::StringSplitter &sp,
							  int &n,
							  ttg::extras::Params *params,
							  std::list<OperationInfo *> &vals,
							  std::list<OperationInfo::OperationName> &ops);
			//"Eats" and returns next operation.
			//Note: never returns NULL.
			static OperationInfo *buildNext(std::list<OperationInfo *> &vals,
											std::list<OperationInfo::OperationName> &ops);
			//Builds by given lexem list corresponding opearation (and returns it or NULL).
			static OperationInfo *build(ttg::strings::StringSplitter &sp,
										int &n,
										ttg::extras::Params *params);
		friend class ttg::extras::Calculator<float>;
		friend class ttg::extras::Calculator<ttg::math::vec3f>;
		friend class ttg::extras::Calculator<ttg::math::vec4f>;
		friend class ttg::extras::Calculator<ttg::math::mat3x3f>;
		friend class ttg::extras::Calculator<ttg::math::mat4x4f>;
	};
}

namespace ttg
{
	namespace extras
	{
		template<class T>
		class Calculator
		{
			public:
				//Returns configured tree of operations or NULL (in case of error).
				static inline Operation<T> *create(const char *value,
												   Params *params)
				{
					if (value != NULL)
					{
						StringSplitter sp;
						sp.setSplitter('(', true);
						sp.setSplitter(')', true);
						sp.setSplitter('+', true);
						sp.setSplitter('-', true);
						sp.setSplitter('*', true);
						sp.setSplitter('/', true);
						sp.setSplitter(',', true);
						sp.setSplitter(' ', false);
						sp.setSplitter('\n', false);
						sp.setString(value);
						int n = 0;
						ttg_internal::OperationInfo *info
								= ttg_internal::CalculatorRoutines::build(sp, n, params);
						if (info != NULL)
							return dynamic_cast<Operation<T> *>(info);
					}
					return NULL;
				}
		};
	}
}

#endif
